package com.waigoulin.service.impl;

import com.google.common.cache.Cache;
import com.waigoulin.common.constants.Constants;
import com.waigoulin.service.ILoginService;
import com.waigoulin.common.lbs.IpLocationUtil;
import com.waigoulin.service.lbs.IpLocationApiService;
import com.waigoulin.domain.vo.WeixinTemplateMessageVO;
import com.waigoulin.domain.req.WeixinQrCodeReq;
import com.waigoulin.domain.res.IpLocationRes;
import com.waigoulin.domain.res.WeixinQrCodeRes;
import com.waigoulin.domain.res.WeixinTokenRes;
import com.waigoulin.service.weixin.IWeixinApiService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import retrofit2.Call;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @FileName WeixinLoginServiceImpl
 * @Description 微信服务
 * @Author waigoulin
 * @date 2025-05-14
 **/
@Service
public class WeixinLoginServiceImpl implements ILoginService {

    @Value("${weixin.config.app-id}")
    private String appid;

    @Value("${weixin.config.app-secret}")
    private String appSecret;

    @Value("${weixin.config.template-id}")
    private String template_id;

    // 微信开发平台api服务相关缓存的配置信息
    // 1. appid 和 access_token
    // 2. ticket 和 openid

    // Guava库的Cache实现缓存（本地缓存）
    @Resource
    // <appid, access_token>
    private Cache<String, String> weixinAccessToken;

    @Resource
    // <ticket, openid>
    private Cache<String, String> openidToken;

    // Redis实现缓存（跨域缓存）
    @Resource
    // RedisTemplate接口
    private RedisTemplate<String, String> redisTemplate;

    // access_token过期时间
    @Value("${weixin.config.access-token.expire-seconds}")
    private long ACCESS_TOKEN_EXPIRE; // 单位：秒

    // openid过期时间
    @Value("${weixin.config.openid.expire-seconds}")
    private long OPENID_EXPIRE; // 单位：秒

    @Resource
    // 微信平台api服务接口
    private IWeixinApiService weixinApiService;

    @Resource
    // ip地址解析api服务接口
    private IpLocationApiService ipLocationApiService;

    @Override
    public String createQrCodeTicket() throws Exception {
        // 1. 获取 access_token
        String accessToken = getAccessToken();

        // 2.生成 ticket
        WeixinQrCodeReq weixinQrCodeReq = WeixinQrCodeReq.builder()
                .expire_seconds(30 * 24 * 60 * 60)
                .action_name(WeixinQrCodeReq.ActionNameTypeVO.QR_SCENE.getCode())
                .action_info(WeixinQrCodeReq.ActionInfo.builder()
                        .scene(WeixinQrCodeReq.ActionInfo.Scene.builder()
                                .scene_id(100601)
                                .build())
                        .build())
                .build();
        Call<WeixinQrCodeRes> call = weixinApiService.createQrCode(accessToken, weixinQrCodeReq);
        WeixinQrCodeRes weixinQrCodeRes = call.execute().body();
        // 断言请求不为null
        assert weixinQrCodeRes != null;
        String ticket = weixinQrCodeRes.getTicket();
        return ticket;
    }

    @Override
    public String checkLogin(String ticket) {
        // 从 Cache 缓存中获取 openid
        // return openidToken.getIfPresent(ticket);

        // 从 Redis 获取 openid
        return redisTemplate.opsForValue().get(buildOpenidKey(ticket));
    }

    @Override
    public void saveLoginState(String ticket, String openid) throws IOException {
        // 缓存<ticket, openid>

        // Cache 存储 <ticket, openid>
        // openidToken.put(ticket, openid);

        // redis 存储 <ticket, openid>
        redisTemplate.opsForValue().set(buildOpenidKey(ticket), openid, OPENID_EXPIRE, TimeUnit.SECONDS);

        // 1. 获取 accessToken 【实际业务场景，按需处理下异常】
        String accessToken = getAccessToken();

        // 2. 发送模板消息
        Map<String, Map<String, String>> data = new HashMap<>();
        // 2.1 添加用户信息
        WeixinTemplateMessageVO.put(data, WeixinTemplateMessageVO.TemplateKey.USER, openid);
        // 2.2 添加登录IP（通过RequestContextHolder获取请求对象）
        String loginIp = IpLocationUtil.getLoginIp();
        WeixinTemplateMessageVO.put(data, WeixinTemplateMessageVO.TemplateKey.IP, loginIp);
        // 2.3 添加登录地区（省份+城市+运营商）
        String loginDistrict = getLoginIpLocation(loginIp);
        WeixinTemplateMessageVO.put(data, WeixinTemplateMessageVO.TemplateKey.DISTRICT, loginDistrict);

        WeixinTemplateMessageVO templateMessageDTO = new WeixinTemplateMessageVO(openid, template_id);
        templateMessageDTO.setUrl("https://gaga.plus");
        templateMessageDTO.setData(data);

        Call<Void> call = weixinApiService.sendMessage(accessToken, templateMessageDTO);
        call.execute();

    }

    /**
     * TODO: 暂时的IP解析服务
     * 根据IP地址解析地理位置（格式：省 市 运营商）
     */
    @Override
    public String getLoginIpLocation(String ip) throws IOException {
        if (ip == null || StringUtils.isBlank(ip) || "127.0.0.1".equals(ip)) {
            return "本地网络";
        }

        Call<IpLocationRes> call = ipLocationApiService.getIpLocation(ip, "true");
        IpLocationRes ipLocationRes = call.execute().body();

        assert ipLocationRes != null;
        // 若没有错误，直接返回接口提供的完整地址
        if (StringUtils.isBlank(ipLocationRes.getError())) {
            return ipLocationRes.getAddress();
        }

        return "未知地点";
    }

    /**
     * 获取AccessToken（从Redis获取或重新获取）
     */
    private String getAccessToken() throws IOException {
        // Guava 库的 Cache 实现缓存 <appid, access_token>
        // 在 Cache 缓存中查找 access_token
//        String accessToken = weixinAccessToken.getIfPresent(appid);
//        // 如果 Cache 缓存中不存在，则调用微信api服务，通过 grant_type 、 appid 和 app_secret 获取 access_token
//        if (StringUtils.isBlank(accessToken)) {
//            // 用 retrofit2 包装微信access_token请求
//            Call<WeixinTokenRes> call = weixinApiService.getToken("client_credential", appid, appSecret);
//            WeixinTokenRes weixinTokenRes = call.execute().body();
//            // 断言请求不为null
//            assert weixinTokenRes != null;
//            accessToken = weixinTokenRes.getAccess_token();
//            weixinAccessToken.put(appid, accessToken);
//        }

        // Redis 实现缓存 <appid, access_token>
        // 在 Redis 缓存中查找 access_token
        String accessToken = redisTemplate.opsForValue().get(buildAccessTokenKey(appid));
        // 如果 Redis 缓存中不存在，则调用微信api服务，通过 grant_type 、 appid 和 app_secret 获取 access_token
        if (StringUtils.isBlank(accessToken)) {
            Call<WeixinTokenRes> call = weixinApiService.getToken("client_credential", appid, appSecret);
            WeixinTokenRes weixinTokenRes = call.execute().body();
            // 断言请求不为null
            assert weixinTokenRes != null;
            accessToken = weixinTokenRes.getAccess_token();
            redisTemplate.opsForValue().set(buildAccessTokenKey(appid), accessToken, ACCESS_TOKEN_EXPIRE, TimeUnit.SECONDS);
        }

        return accessToken;
    }

    /**
     * 构建AccessToken的Redis键
     */
    private String buildAccessTokenKey(String appid) {
        return Constants.REDIS_WEIXIN_PREFIX + Constants.RedisKeyEnum.ACCESS_TOKEN.getKeyPrefix() + appid;
    }

    /**
     * 构建openid的Redis键
     */
    private String buildOpenidKey(String ticket) {
        return Constants.REDIS_WEIXIN_PREFIX + Constants.RedisKeyEnum.OPENID_TOKEN.getKeyPrefix() + ticket;
    }


}


